﻿#region using

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

#endregion

namespace JupiterLibrary
{
    /// <summary>
    /// Un Sprite es un Rectangulo formato por 4 vertices, con posibilidad de color y textura
    /// </summary>
    public class Ring
    {
        VB vb;

        public Texture_2D Texture;

        public float StartAngle;

        public float EndAngle;

        public float InnerRadius;

        /// <summary>
        /// Cuanto mayor es el nº menos resolución tiene. Un valor de 5 es una gran resolución
        /// </summary>
        float teselationFactor = 10f;

        public Vector3 Position;
        public float Radius;
        int numTriangles;
        public Color Color=Color.Red;

        public Ring(float startAngle,float endAngle,float radius,float innerRadius)
        { 
            this.StartAngle = startAngle;
            this.EndAngle = endAngle;
            InnerRadius = innerRadius;

            // Create the VertexBuffer object
            vb = Jupiter.Video.VertexBuffers.CreateAndAdd();

            Radius = radius;
        }

        void Build()
        {
            int numPoints = (int)((EndAngle - StartAngle) / teselationFactor);

            if (numPoints == 0) return;

            double angle=MathHelper.ToRadians(StartAngle);

            double incAngle=MathHelper.ToRadians(((EndAngle - StartAngle)/numPoints));

            //numPoints = 10;

            //incAngle = MathHelper.ToRadians(30) / numPoints;

            // Debemos multiplicar por 2 si tenemos un inner radius, pq duplicamos el nº de triangulos

            int numVertices = numPoints * 3;

            numTriangles = numPoints;

            if (InnerRadius > 0) { numVertices *= 2; numTriangles *= 2; }

            vb.Position = new Vector3[numVertices];

            vb.Color = new Color[numVertices];

            for (int i = 0; i < numVertices; i++)
                vb.Color[i] = Color;

            int j = 0;

            Vector3 dir = Vector3.Zero;

            for (int i = 0; i < numPoints; i++)
            {
                Vector3 finalPos = new Vector3((float)Math.Cos(angle) * Radius, (float)Math.Sin(angle) * Radius, 0);

                Vector3 centerPos = Position;

                vb.Position[j++] = finalPos + centerPos;

                if (InnerRadius > 0)
                {
                    // Buscamos ahora el vector para hallar el InnerRadius

                    dir = Vector3.Normalize(finalPos);
                }

                angle += incAngle;

                finalPos = new Vector3((float)Math.Cos(angle) * Radius, (float)Math.Sin(angle) * Radius, 0);

                vb.Position[j++] = finalPos + centerPos;

                if (InnerRadius > 0)
                {
                    // El centro ahora se mueve
                    vb.Position[j++] = centerPos + dir * InnerRadius;

                    // Añado ahora el triángulo que une los espacios que quedan enmedio

                    vb.Position[j++] = finalPos + centerPos;
                    vb.Position[j+1] = centerPos + dir * InnerRadius;

                    // Me falta calcular el siguiente

                    angle += incAngle;

                    finalPos = new Vector3((float)Math.Cos(angle) * Radius, (float)Math.Sin(angle) * Radius, 0);
                    dir = Vector3.Normalize(finalPos);
                    vb.Position[j+0] = centerPos + dir * InnerRadius;

                    j += 2;

                    angle -= incAngle;
                }
                else
                {
                    vb.Position[j++] = centerPos;
                }
            }

            // Inform the VB that the values have changed
            vb.Dirty = true;
        }

        public void Update()
        {
            Build();
        }

        public void Draw()
        {
            if (vb.Position == null) return;

            // Bind the VertexBuffer to the device
            vb.SetToDevice();

            // Access to the basicEffect
            BasicEffect basicEffect = Jupiter.Video.BasicEffect;
            
            if (Texture == null)
                basicEffect.Texture = null;
            else
                basicEffect.Texture=Texture.Texture;

            basicEffect.TextureEnabled = (basicEffect.Texture != null);

            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
            {
                pass.Apply();

                Jupiter.Video.GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, numTriangles);
            }
        }
    }
}
